package bg.consulting.labo;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.media.CaptureDeviceInfo;
import javax.media.CaptureDeviceManager;
import javax.media.ControllerErrorEvent;
import javax.media.ControllerEvent;
import javax.media.ControllerListener;
import javax.media.DataSink;
import javax.media.Format;
import javax.media.Manager;
import javax.media.MediaLocator;
import javax.media.Player;
import javax.media.Processor;
import javax.media.ProcessorModel;
import javax.media.RealizeCompleteEvent;
import javax.media.StopEvent;
import javax.media.datasink.DataSinkErrorEvent;
import javax.media.datasink.DataSinkEvent;
import javax.media.datasink.DataSinkListener;
import javax.media.datasink.EndOfStreamEvent;
import javax.media.format.AudioFormat;
import javax.media.protocol.ContentDescriptor;
import javax.media.protocol.DataSource;
import javax.media.protocol.FileTypeDescriptor;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JPanel;

import bg.consulting.labo.util.UtilSwing;


public class MicroMediaPlayer implements ControllerListener {

	//JComboBox comboBoxCaptureDevice;
	//JComboBox comboBoxFormat = new JComboBox();
	Player player;
	JPanel panelGlobal = new JPanel();
	/** Processor used to transcode the media. */
	protected Processor processor;
	File fileDestination = new File("capturedSound3.wav");
	/** Sink used to "write" out the transcoded media. */
	protected DataSink dataSink;

	private JCheckBox checkBoxMute = new JCheckBox("Muet");
	/**
	 * Model used in constructing the processor, and which specifies track
	 * formats and output content type
	 */
	protected ProcessorModel processorModel;

	/** Output of the Processor: the transcoded media. */
	protected DataSource dataSource;

	public JPanel getPanelGlobal() {
		return panelGlobal;
	}

	public static void main(String[] a) {
		MicroMediaPlayer micro = new MicroMediaPlayer();
		JFrame frame = new JFrame();
		frame.add(micro.getPanelGlobal());
		UtilSwing.initFrame(frame);
	}

	public MicroMediaPlayer() {
		initFile();
		initSwing();
	}
	
	private void initFile() {
		try {
			if (!fileDestination.exists()){
				this.fileDestination.delete();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	private void initSwing() {
		
		
		JButton buttonRecordInit= new JButton("Init");
		buttonRecordInit.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				initRecord();
			}
		});
		JButton buttonRecordStop = new JButton("stop");
		buttonRecordStop.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				stopRecord();
			}
		});
		JButton buttonRecord = new JButton("record");
		buttonRecord.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				startRecord();
			}
		});
		JButton buttonStart = new JButton("start");
		buttonStart.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				startPlayer();
			}
		});
		this.checkBoxMute.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				System.out.println("checkBoxMute actionevent: " + e);
				doMute();
			}
		});
			panelGlobal.add(checkBoxMute);
		panelGlobal.add(buttonStart);
		panelGlobal.add(buttonRecordInit);
		panelGlobal.add(buttonRecord);
		panelGlobal.add(buttonRecordStop);
	}

	

	private void doMute() {
		boolean isMute = this.checkBoxMute.isSelected();
		System.out.println("Mute doMute" + isMute);

		if (isMute) {
			System.out.println("Mute stop " + this.checkBoxMute.isSelected());
			this.player.stop();
		} else {
			System.out.println("Mute start");
			this.player.start();
		}
	}

	private void startPlayer() {
		try {
			CaptureDeviceInfo cdi = CaptureDeviceManager.getDevice("DirectSoundCapture");
			System.out.println("start " + cdi);
			player = Manager.createPlayer(cdi.getLocator());

			player.start();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	

	private void initRecord() {
		try {
			CaptureDeviceInfo cdi = CaptureDeviceManager.getDevice("DirectSoundCapture");
			MediaLocator mediaLocatorSource = cdi.getLocator();
			System.out.println("intRecord " + cdi);
			Format[] formatsArray = new Format[1];
			formatsArray[0] = new AudioFormat(AudioFormat.LINEAR);
			ContentDescriptor contentDescriptor = new ContentDescriptor(FileTypeDescriptor.WAVE);
							processorModel = new ProcessorModel(mediaLocatorSource, formatsArray, contentDescriptor);
			processor = Manager.createRealizedProcessor(processorModel);
			processor.addControllerListener(this);
			System.out.println(" processor state : "+processor.getState()+"   "+Processor.Realized);
			Thread.sleep(3000);
			System.out.println(" processor state : "+processor.getState());
			float rate = 1.0f;			
			float translationRate = processor.setRate((float) Math.abs(rate));
			this.dataSource = processor.getDataOutput();
			
			MediaLocator mediaLocatorDestination = new MediaLocator(""+this.fileDestination.toURI());
			
			this.dataSink = Manager.createDataSink(dataSource, mediaLocatorDestination);
			dataSink.addDataSinkListener(new DataSinkListener() {
				public void dataSinkUpdate(DataSinkEvent e) {
					System.out.println("dataSinkUpdate DataSinkEvent e :");
					if (e instanceof EndOfStreamEvent) {
						dataSink.close();
						dataSource.disconnect();
					} else if (e instanceof DataSinkErrorEvent) {
						if (dataSink != null)
							dataSink.close();
						if (dataSource != null)
							dataSource.disconnect();
					}
				}
			});
			System.out.println("startRecord done : file exists: AAAA "+fileDestination.exists()+"  "+fileDestination.getAbsolutePath() );
			processor.start();
			System.out.println("startRecord done : file exists: BBBBB "+fileDestination.exists()+"  "+fileDestination.getAbsolutePath() );
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	private void startRecord() {
		System.out.println("StartRecord fileDestination.exists :"+this.fileDestination.exists()+"  size: "+this.fileDestination.length());
		System.out.println("StartRecord dataSink.getOutputLocator :"+this.dataSink.getOutputLocator());
		try {
			this.dataSink.open();
			this.dataSink.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void stopRecord() {
		System.out.println("StopRecord fileDestination.exists :"+this.fileDestination.exists()+"  size: "+this.fileDestination.length());
		try {
			//this.dataSink.stop();
			//this.dataSink.close();
			this.processor.stop();
	       
		} catch (Exception e) {
			e.printStackTrace();
		}
		System.out.println("StopRecord fileDestination.exists :"+this.fileDestination.exists()+"  size: "+this.fileDestination.length());
		
	}

	public static List getListAudioCaptureDeviceName() {
		Vector v = CaptureDeviceManager.getDeviceList(null);
		List<String> listAudioCAptureDevice = new ArrayList<String>();
		for (Object o : v) {
			CaptureDeviceInfo cdi = (CaptureDeviceInfo) o;
			boolean isAudio = cdi.getFormats()[0] instanceof AudioFormat;
			System.out.println("    " + cdi.getName() + "  isAudio :" + isAudio);
			if (isAudio) {
				listAudioCAptureDevice.add(cdi.getName());
			}
		}
		System.out.println("getListAudioCaptureDevice: size:" + listAudioCAptureDevice.size());
		return listAudioCAptureDevice;
	}

	@Override
	public void controllerUpdate(ControllerEvent event) {
		System.out.println("controllerUpdate ControllerEvent "+getProcessorState()+" event : " + event);
		if (event instanceof StopEvent) {
			System.out.println("controllerUpdate ControllerEvent StopEvent !!!!!!!!!!!!!!");
			processor.close();
			// if (state == TRANSLATING) state = TRANSFERRING;
		}
		// Transcoding failed.
		else if (event instanceof ControllerErrorEvent) {
			System.out.println("controllerUpdate ControllerEvent ControllerErrorEvent !!!!!!!!!!!!!");
			processor.removeControllerListener(this);
			processor.close();
			// state = FAILED;
		}else if (event instanceof RealizeCompleteEvent){
			System.out.println("controllerUpdate ControllerEvent Yes Realize Termined !!!!!!!!!!!!!");
		}
		
		
	}
	private String getProcessorState(){
		int state = this.processor.getState();
		String r ="";
		if (state == 300){
			r ="REALIZED";
		}else if(state==400){
			r="PREFETCHING";
		}else if(state==500){
			r="PREFETCHED";
		}else if(state==600){
			r="STARTED";
		}
		return state+" "+r;
	}
	
}
